/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

#ifndef CVML_BINARY_FORMAT_HPP
#define CVML_BINARY_FORMAT_HPP

static const u4 MAGIC = 0xD166175;
static const u1 MAJOR = 0;
static const u1 MINOR = 1; 

struct Binary : Serializable
{
	Array<u2, u2> const_indexes; 
	Array<u2, u1> const_data;
	u2 num_fxns;
	Array<u2, u2> fxn_indexes; 
	Array<u2, u1> code; 

	void Serialize(Stream& stream)
	{
		if (stream.IsReading())
		{
			u4 testMagic;
			u1 testMajor;
			u1 testMinor;
			stream.Read(testMagic);
			stream.Read(testMajor);
			stream.Read(testMinor);
			if (testMagic != MAGIC)
				throw "incorrect magic number";
			if (testMajor != MAJOR)
				throw "unsupported major version";
			if (testMinor != MINOR)
				throw "unsupported minor version";
		}
		else
		{
			stream.Write(MAGIC);
			stream.Write(MAJOR);
			stream.Write(MINOR);
		}

		stream.Serialize(num_fxns);
		const_indexes.Serialize(stream);
		const_data.Serialize(stream);
		code.Serialize(stream);

		if (stream.IsReading()) {
			fxn_indexes.Reallocate(num_fxns);
			fxn_indexes[0] = 0;
			int cur_fxn = 1;
			int i=0; 
			while (i < code.Count()) {
				OpCodeEnum op = (OpCodeEnum)code[i];
				i += GetOpCodeWidth(op);
				if (IsSubTerminator(op))
					if (cur_fxn < num_fxns)
						fxn_indexes[cur_fxn++] = i;
			}
		}
	}

	u1* GetConst(int n)
	{
		return &const_data[const_indexes[n]];
	}

	u1* GetFxn(int n)
	{
		return &code[fxn_indexes[n]];
	}

	u4 GetTotalSize() {
		return const_indexes.GetTotalSize() + const_data.GetTotalSize() 
			+ sizeof(num_fxns) + code.GetTotalSize() + 
			sizeof(MAGIC) + sizeof(MAJOR) + sizeof(MINOR);
	}
};

#endif
